Conversation
280de10 to
dcc5ab4
Compare
…every VALIDATION_ERROR
When a discriminated-union (`oneOf`) shape fails validation because the
caller used the wrong key as the discriminator (the v3 reference-seller
`pricing_options` regression: `{"type": "cpm", ...}` instead of
`{"pricing_model": "cpm", ...}`), an additive `hint` field on the
`VALIDATION_ERROR` issue names the closest matching variant and the
wrong / expected discriminator keys:
Looks like you may have meant the 'cpm' variant. Use
'pricing_model' instead of 'type' as the discriminator.
The hint is best-effort: when no clear winner exists across variants,
no hint is emitted (silent is better than misleading). Clients that
ignore the new field behave exactly as before — `hint` is only added
to the wire envelope's `issues[i]` dict when populated.
Heuristic (in `adcp.validation.oneof_hints.compute_oneof_hint`):
1. Walk to the schema's `oneOf` keyword via the failing issue's
`absolute_schema_path`.
2. Detect the discriminator field — a property pinned by `const` in
at least two variants. No discriminator -> no hint.
3. Score each variant by `(const_match, required_present, total_present)`:
the strongest signal is whether any value in the payload matches a
variant's discriminator `const` (the wrong-key case); shape match
is the tiebreaker. Tie at the top -> no hint.
4. Identify the wrong key in the payload — first key whose value
matches the best variant's `const`, or first key not declared by
any variant's `properties`.
Plumbed through `validate_request` / `validate_response` (which now
forward the validator's resolved schema + payload to `_format_error`)
and surfaced via the existing `_issue_to_wire` helper used by both
`SchemaValidationError.details` and
`build_adcp_validation_error_payload`.
Closes #460. Refs #452.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dcc5ab4 to
38b958f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When a discriminated-union (
oneOf) shape fails validation because the caller used the wrong key as the discriminator — the v3 reference-sellerpricing_optionsregression where an LLM client submits{"type": "cpm", ...}instead of{"pricing_model": "cpm", ...}— emit an additivehintfield on theVALIDATION_ERRORissue:adcp.validation.oneof_hints.compute_oneof_hintheuristic — pure, schema-driven, no Pydantic dependency (the framework's validator is jsonschema-based).ValidationIssuegains an optionalhint: str | None = Nonefield._format_errornow accepts the validator's resolved schema + payload, computes the hint when keyword ==oneOf, and attaches it._issue_to_wireonly writeshintto the wire dict when populated, so clients that ignore the new field see exactly the pre-hint envelope shape — additive change.The hint is best-effort: when no clear winner exists across variants, no hint is emitted (silent is better than misleading).
Heuristic
oneOfkeyword via the failing issue'sabsolute_schema_path.constin at least two variants. No discriminator → no hint.(const_match, required_present, total_present). The strongest signal is whether any value in the payload matches a variant's discriminatorconst(the wrong-key case); shape match is the tiebreaker. Tie at the top → no hint.const, or first key not declared by any variant'sproperties.Projection point
adcp.validation.schema_validator._format_errorprojects every jsonschemaValidationErrorinto aValidationIssue. Two callers (validate_request/validate_response) now forwardvalidator.schemaand the payload through. The wire envelope is produced by_issue_to_wire(used by bothSchemaValidationError.detailsandbuild_adcp_validation_error_payloadinschema_errors.py).Divergences from JS commit
e7f8e228@adcp/sdk@6.7'se7f8e228lands three things:not-failure variants when picking the best surviving oneOf variant — about Success/Error response envelope mutual exclusion.The
hint-emitting near-miss feature described by issue #460 is not implemented as a single named function in JS; it's the design intent the issue spec calls out. This PR builds it for Python directly, using the regression class (typevspricing_modelonpricing_options) as the load-bearing test case. The JSnot-failure exclusion is orthogonal and can be ported separately if needed.Test plan
pytest tests/test_oneof_hints.py -v— 12 new tests, all passtypeinstead ofpricing_model) produces a hint naming thecpmvariant +pricing_modelvstypeget_productsschemaconstmatches caller's valuepytest tests/— 3442 passed, 27 skipped, 1 xfailed; no regressionsruff checkclean on touched filesmypyclean on touched implementation filesCloses #460. Refs #452.
🤖 Generated with Claude Code